package com.jay.fault.retry;

import com.github.rholder.retry.*;
import com.jay.model.RpcResponse;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 固定时间间隔 - 重试策略
 * 本类实现了重试策略接口，定义了一种固定时间间隔的重试机制
 * 主要用于在远程过程调用（RPC）中遇到异常时，按照固定的时间间隔进行重试
 */
@Slf4j
public class FixedIntervalRetryStrategy implements RetryStrategy {

    /**
     * 执行重试操作
     * 本方法使用固定的时间间隔作为重试策略，当遇到异常时按照设定的间隔进行重试
     *
     * @param callable 一个 Callable 任务，代表需要执行的 RPC 操作
     * @return 返回 RpcResponse 对象，包含 RPC 调用的结果
     * @throws ExecutionException 如果在执行任务或重试过程中遇到异常
     * @throws RetryException 如果重试次数达到最大尝试次数后仍然失败
     */
    public RpcResponse doRetry(Callable<RpcResponse> callable) throws ExecutionException, RetryException {
        // 构建一个重试器，定义了重试的规则和策略
        Retryer<RpcResponse> retryer = RetryerBuilder.<RpcResponse>newBuilder()
                // 如果出现 Exception 类型的异常就进行重试
                .retryIfExceptionOfType(Exception.class)
                // 设置固定时间间隔的等待策略，每次重试之间等待 3 秒
                .withWaitStrategy(WaitStrategies.fixedWait(3L, TimeUnit.SECONDS))
                // 设置停止策略，最大尝试次数为 3 次
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                // 设置重试监听器，在每次重试时记录日志
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        // 记录当前重试的次数
                        log.info("重试次数 {}", attempt.getAttemptNumber());
                    }
                })
                // 构建重试器
                .build();
        // 使用重试器执行 Callable 任务，并返回结果
        return retryer.call(callable);
    }

}
